﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Threading.Tasks;

namespace UnvApi
{
    public class UnvHttpMethods
    {
        public static async Task<string> sendMessageAsync(string uri, string username, string password, string method, string requestBody)
        {
            //预设返回值
            string responseBody = "";
            // Digest鉴权所需的参数  
            string realm = "";
            string nonce = "";

            // 创建HttpClient实例  
            using (var client = new HttpClient())
            {
                // 准备POST请求的内容  
                var content = new StringContent(requestBody, Encoding.UTF8, "application/json");

                // 发送POST请求，以获取Digest鉴权信息  
                HttpResponseMessage response = await client.PostAsync(uri, content);
                //HttpResponseMessage response = await client.GetAsync(uri);

                // 确保请求成功（不需要，宇视渣系统在返回digest信息时用的是失败码，用的话这里过不去）
                //response.EnsureSuccessStatusCode();

                //// 读取并输出响应的头部信息  
                //foreach (var header in response.Headers)
                //{
                //    Console.WriteLine("{0}: {1}", header.Key, header.Value.First());
                //    //if (header.Key == "WWW-Authenticate")
                //    //{
                //    //    Console.WriteLine("WWW-Authenticate: " + header.Value.First());
                //    //}
                //}

                // 读取特定的头部，比如WWW-Authenticate
                if (response.Headers.TryGetValues("WWW-Authenticate", out var AuthenticateValues))
                {
                    //Console.WriteLine("WWW-Authenticate: " + string.Join(", ", AuthenticateValues));
                    //WWW-Authenticate: Digest realm="234a21b44f0f",nonce="98217e8e8ce481c31e71ca00d08925d6",stale="AUTH"
                    string Authenticate = string.Join(", ", AuthenticateValues);
                    //Console.WriteLine("Authenticate: " + Authenticate);
                    realm = Authenticate.Substring(Authenticate.IndexOf("realm=\"") + 7);
                    realm = realm.Substring(0, realm.IndexOf("\""));
                    //Console.WriteLine(realm);
                    nonce = Authenticate.Substring(Authenticate.IndexOf("nonce=\"") + 7);
                    nonce = nonce.Substring(0, nonce.IndexOf("\""));
                    //Console.WriteLine(nonce);

                }

                // 创建Digest鉴权头部  
                string authHeader = CreateDigestAuthorizationHeader(username, password, realm, uri, method, nonce);
                //Console.WriteLine(authHeader);

                // 确定要用的htttp方法
                HttpMethod httpMethod;
                switch (method)
                {
                    case "PUT":
                        httpMethod = HttpMethod.Put;
                        break;
                    case "DELETE":
                        httpMethod = HttpMethod.Delete;
                        break;
                    case "GET":
                        httpMethod = HttpMethod.Get;
                        break;
                    default:
                        httpMethod = HttpMethod.Post;
                        break;
                }
                // 设置请求头
                HttpRequestMessage request = new HttpRequestMessage(httpMethod, uri)
                {
                    Content = content,
                    Headers =
                    {
                        { HttpRequestHeader.Authorization.ToString(), authHeader },  
                        // 如果服务器要求其他头部，可以在这里添加，比如 Content-Type  
                    }
                };

                try
                {
                    // 发送请求  
                    response = await client.SendAsync(request);
                    response.EnsureSuccessStatusCode(); // 确保请求成功  
                    responseBody = await response.Content.ReadAsStringAsync(); // 读取响应内容  
                    //Console.WriteLine(responseBody); // 输出响应内容  
                    
                }
                catch (HttpRequestException e)
                {
                    Console.WriteLine("\nException Caught!");
                    Console.WriteLine("Message :{0} ", e.Message);
                    responseBody = "请求失败:\n" + e.Message;
                }
                client.Dispose();
            }
            return responseBody;
        }

        /// <summary>
        /// 生成Digest认证Header
        /// </summary>
        /// <param name="username">用户名</param>
        /// <param name="password">密码</param>
        /// <param name="uri">请求的uri</param>
        /// <param name="method">请求方式（POST、GET等）</param>
        /// <param name="realm">服务器提供的realm</param>
        /// <param name="nonce">服务器生成的随机数</param>
        /// <returns></returns>
        private static string CreateDigestAuthorizationHeader(string username, string password, string realm, string uri, string method, string nonce)
        {
            // HA1 = MD5(username:realm:password)  
            string ha1 = CalculateMd5Hash($"{username}:{realm}:{password}");

            // HA2 = MD5(method:uri)  
            string ha2 = CalculateMd5Hash($"{method}:{uri}");

            // Response = MD5(HA1:nonce:nc:cnonce:qop:HA2),此系统无nc、cnonce、qop，省略
            string response = CalculateMd5Hash($"{ha1}:{nonce}:{ha2}");

            // Authorization header value  
            string authHeader = $"Digest username=\"{username}\", realm=\"{realm}\", nonce=\"{nonce}\", uri=\"{uri}\", response=\"{response}\"";
            return authHeader;
        }

        /// <summary>
        /// 将明文基于MD5转为十六进制字符串
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        static string CalculateMd5Hash(string input)
        {
            // 创建一个MD5对象  
            using (MD5 md5Hash = MD5.Create())
            {
                // 计算输入字符串的哈希值  
                byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));

                // 创建一个StringBuilder来收集字节并转换为十六进制字符串  
                StringBuilder sBuilder = new StringBuilder();

                // 遍历data中的每一个字节并格式化为十六进制字符串  
                for (int i = 0; i < data.Length; i++)
                {
                    sBuilder.Append(data[i].ToString("x2"));
                }

                // 返回十六进制字符串  
                return sBuilder.ToString();
            }
        }

        public static string generateJsonString(Object input)
        {
            // 配置JsonSerializerOptions以保持中文字符原样输出
            var options = new JsonSerializerOptions
            {
                Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
            };

            // 使用配置后的选项序列化对象为JSON字符串
            string jsonString = "";
            try
            {
                jsonString = JsonSerializer.Serialize(input, options);
                Console.WriteLine(jsonString);

            }
            catch (Exception ex)
            {
                Console.WriteLine($"序列化过程中发生错误: {ex.Message}");
            }
            return jsonString;
        }
    }
}
